﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Collections.Generic;
using System.Resources;
using System.Globalization;
using System.Windows.Markup;
using System.IO;
using System.Xml;

namespace UIT.Sl.Utils
{
	public static class Extensions
	{
		private static Dictionary<Assembly, ResourceDictionary> resources = new Dictionary<Assembly, ResourceDictionary>();

		public static ResourceDictionary GetAssemblyResource(Assembly assembly)
		{
			ResourceDictionary dict;
			lock (assembly)
			{
				if (resources.TryGetValue(assembly, out dict))
					return dict;

				ResourceDictionary xamlDict = TryBuildDict("/" + assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')) + ";component/themes/generic.xaml");
				ResourceDictionary xbfDict = TryBuildDict("/" + assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')) + ";component/themes/generic.xbf");
				if (xamlDict == null)
					return xbfDict;
				if (xbfDict == null)
					return xamlDict;

				dict = new ResourceDictionary() { MergedDictionaries = { xamlDict, xbfDict } };
				resources.Add(assembly, dict);

				return dict;

			}
		}

		private static ResourceDictionary TryBuildDict(string uri)
		{
			try
			{
				return new ResourceDictionary { Source = new Uri(uri, UriKind.Relative) };
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static Stream CorrectClrNamespace(Stream serializedDict, string assemblyName)
		{
			Stream ms = new MemoryStream((int)serializedDict.Length);
			XmlReader reader = XmlReader.Create(serializedDict);
			XmlWriter writer = XmlWriter.Create(ms, new XmlWriterSettings() { OmitXmlDeclaration = true });
			bool preventReading = false;
			while (preventReading || reader.Read())
			{
				preventReading = false;
				switch (reader.NodeType)
				{
					case XmlNodeType.Attribute:
						string value = reader.Value;
						if (reader.LocalName == "xmlns" && value.StartsWith("clr-namespace:") && !value.Contains(",assembly="))
							value += ";assembly=" + assemblyName;
						writer.WriteAttributeString(reader.LocalName, reader.NamespaceURI, value);
						preventReading = reader.MoveToNextAttribute();
						break;
					case XmlNodeType.CDATA:
						writer.WriteCData(reader.Value);
						break;
					case XmlNodeType.Comment:
						writer.WriteComment(reader.Value);
						break;
					case XmlNodeType.Document:
						writer.WriteStartDocument();
						break;
					case XmlNodeType.DocumentFragment:
						throw new NotImplementedException();
					case XmlNodeType.DocumentType:
						writer.WriteDocType(reader.Name, null, null, reader.Value);
						break;
					case XmlNodeType.Element:
						writer.WriteStartElement(reader.LocalName, reader.NamespaceURI);
						preventReading = reader.MoveToFirstAttribute();
						break;
					case XmlNodeType.EndElement:
						writer.WriteEndElement();
						break;
					case XmlNodeType.EndEntity:
					case XmlNodeType.Entity:
						throw new NotImplementedException();
					case XmlNodeType.EntityReference:
						writer.WriteEntityRef(reader.Name);
						break;
					case XmlNodeType.Notation:
						break;
					case XmlNodeType.ProcessingInstruction:
						writer.WriteProcessingInstruction(reader.Name, reader.Value);
						break;
					case XmlNodeType.SignificantWhitespace:
						writer.WriteEntityRef("nbsp");
						break;
					case XmlNodeType.Text:
						writer.WriteString(reader.Value);
						break;
					case XmlNodeType.Whitespace:
						writer.WriteWhitespace(reader.Value);
						break;
					case XmlNodeType.XmlDeclaration:
						writer.WriteProcessingInstruction("xml", reader.Name);
						break;
					default:
						break;
				}
			}
			ms.Position = 0;
			return ms;
		}

		public static T FindResource<T>(object key)
		{
			foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
			{
				var dict = GetAssemblyResource(assembly);
				if (dict == null)
					continue;
				var result = dict[key];
				if (result == null)
					continue;
				return (T)result;
			}
			return default(T);
		}
	}
}
